package ex1.controller;

import java.util.Date;
import java.util.Scanner;

import ex1.model.Container;
import ex1.model.ThreadProdutoInterno;

public class Main {
	
	public static int m, k;
	public static final int WORK_LOAD = 10;
	
	public static void main( String[] args ){
		m = k = 0;
		int opt = -1;
		Scanner in = new Scanner(System.in);
		String entrada = "";
		String[] split;
		
		if( args.length != 1 || ! args[0].matches("\\-[123]") ) {
			System.out.println( "usage: -[1 2 3]" );
			System.exit(-1);
		}
		
		opt = Integer.parseInt( args[0].replace("-", "") );
		
		do {
			System.out.print( "Entre com m e k: ");
			try {
				entrada = in.nextLine().trim();
				split = entrada.split(" ");
				m = Integer.parseInt( split[0] );
				k = Integer.parseInt( split[1] );
			} catch( Throwable t ) {
				//t.printStackTrace();
				m = k = -1;
				continue;
			}
			
			if( m == 0 || k == 0 ) continue;
			
			switch( opt ) {
			case 1: e1(); break;
			case 2: e2(); break;
			case 3: e3(); break;
			}
		} while( m != 0 && k != 0 );
	}
	
	/***
	 * O main faz todos os calculos...
	 */
	public static void e1() {
		int i = 0, j = 0, pi = 0;
		long diffMilli = 0l;
		
		Container.set( m, k );
		Date inicio, fim;
		
		inicio = new Date();
		
		for( i = 0; i < m; ++i ) {
			pi = 0;
			for( j = 0; j < k; ++j ) {
				pi += ( Container.matrix[i][j] * Container.matrixTrans[j][i] );
			}
			Container.pis[i] = pi;
		}
		
		fim = new Date();
		diffMilli = fim.getTime() - inicio.getTime();
		
		Container.findMinMaxPi();
		
		System.out.println( "Tempo: " + diffMilli );
		
		System.out.printf( "Maior valor: %d - i: %d, j: %d\n", Container.maxValue.value, Container.maxValue.i, Container.maxValue.j );
		System.out.printf( "Menor valor: %d - i: %d, j: %d\n", Container.minValue.value, Container.minValue.i, Container.minValue.j );
		
		System.out.printf( "Maior Produto Interno: %d - i: %d\n", Container.maxPiValue.value, Container.maxPiValue.i );
		System.out.printf( "Menor Produto Interno: %d - i: %d\n", Container.minPiValue.value, Container.minPiValue.i );
	}
	
	/***
	 * Uma thread para cada Produto interno
	 */
	public static void e2() {
		ThreadProdutoInterno[] threads;
		int i = 0;
		long diffMilli = 0l;
		
		Container.set( m, k );
		Date inicio, fim;
		
		threads = new ThreadProdutoInterno[m];
		for( i = 0; i < m; ++i ) {
			threads[i] = new ThreadProdutoInterno(i, 1);
		}
		
		inicio = new Date();
		
		for( i = 0; i < m; ++i ) {
			threads[i].start();
		}
		
		for( i = 0; i < m; ++i ) {
			try {
				threads[i].join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		fim = new Date();
		
		diffMilli = fim.getTime() - inicio.getTime();
		
		Container.findMinMaxPi();
		
		System.out.println( "Tempo: " + diffMilli );
		
		System.out.printf( "Maior valor: %d - i: %d, j: %d\n", Container.maxValue.value, Container.maxValue.i, Container.maxValue.j );
		System.out.printf( "Menor valor: %d - i: %d, j: %d\n", Container.minValue.value, Container.minValue.i, Container.minValue.j );
		
		System.out.printf( "Maior Produto Interno: %d - i: %d\n", Container.maxPiValue.value, Container.maxPiValue.i );
		System.out.printf( "Menor Produto Interno: %d - i: %d\n", Container.minPiValue.value, Container.minPiValue.i );
	}
	
	/***
	 * Uma thread para cada 10 produtos internos e o mais faz o resto
	 */
	public static void e3() {
		ThreadProdutoInterno[] threads = null;
		int i = 0, j = 0, pi = 0;
		long diffMilli = 0l;
		int div = (int) m / WORK_LOAD;
		int mainPiNum = m % WORK_LOAD;
		int mainPiStart = div * WORK_LOAD;
			
		Container.set( m, k );
		Date inicio, fim;
		
		if( div > 0 ) {
			threads = new ThreadProdutoInterno[div];
		
			for( i = 0; i < div; ++i ) {
				threads[i] = new ThreadProdutoInterno(i, WORK_LOAD);
			}
		}
		
		inicio = new Date();
		
		if( div > 0 ) {
			for( i = 0; i < div; ++i ) {
				threads[i].start();
			}
		}
		
		for( i = 0; i < mainPiNum; ++i ) {
			for( j = 0; j < k; ++j ) {
				pi += ( Container.matrix[mainPiStart+i][j] * Container.matrixTrans[j][mainPiStart+i] );
			}
			Container.pis[mainPiStart+i] = pi;
		}
		
		for( i = 0; i < div; ++i ) {
			try {
				threads[i].join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		fim = new Date();
		
		diffMilli = fim.getTime() - inicio.getTime();
		
		Container.findMinMaxPi();
		
		System.out.println( "Tempo: " + diffMilli );
		
		System.out.printf( "Maior valor: %d - i: %d, j: %d\n", Container.maxValue.value, Container.maxValue.i, Container.maxValue.j );
		System.out.printf( "Menor valor: %d - i: %d, j: %d\n", Container.minValue.value, Container.minValue.i, Container.minValue.j );
		
		System.out.printf( "Maior Produto Interno: %d - i: %d\n", Container.maxPiValue.value, Container.maxPiValue.i );
		System.out.printf( "Menor Produto Interno: %d - i: %d\n", Container.minPiValue.value, Container.minPiValue.i );
	}
}
